package controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import javax.swing.event.MouseInputAdapter;

import command.ICommand;
import command.Invoker;
import command.TranslateYCommand;
import command.TranslateXCommand;
import command.TranslateTwoStepCommand;
import command.ZoomInCommand;
import command.ZoomOutCommand;

import model.Image;
import model.Perspective;
import view.ImagePanel;

public class ImagePanelController {
	
	private ImagePanel imagePanel;
	private Image image;
	private Perspective perspective;
	private Invoker invoker;
	private ICommand firstCommand;
	private ICommand secondCommand;
	private ICommand command;
	private static final boolean USING_LIMIT_OF_FRAME = true;
	
	public ImagePanelController(ImagePanel imagePanel, Image image, Perspective perspective, MenuController menuControl) {
		this.imagePanel = imagePanel;
		this.image = image;
		this.perspective = perspective;
		
		this.imagePanel.addTranslationListener(new TranslationMouseListener());
		this.imagePanel.addZoomListener(new ZoomMouseListener());
		
	}
	
	public ImagePanelController(ImagePanel imagePanel, Image image, Perspective perspective) {
		this.imagePanel = imagePanel;
		this.image = image;
		this.perspective = perspective;
		
		this.imagePanel.addTranslationListener(new TranslationMouseListener());
		this.imagePanel.addZoomListener(new ZoomMouseListener());
	}
	
	class AnnulerMenuListener implements ActionListener {
		 
		@Override
		public void actionPerformed(ActionEvent arg0) {
			invoker = Invoker.getInstance();
			invoker.undo();
		}
	}
	
	class RefaireMenuListener implements ActionListener {
		 
		@Override
		public void actionPerformed(ActionEvent arg0) {
			invoker = Invoker.getInstance();
			invoker.redo();
		}
	}
	
	class TranslationMouseListener extends MouseInputAdapter {
		
		private int mouseXClicked;
		private int originalMouseXClicked;
		private int mouseXReleased;
		private int mouseYClicked;
		private int originalMouseYClicked;
		private int mouseYReleased;
		private int xTranslation;
		private int yTranslation;
		
		@Override
		public void mousePressed(MouseEvent e) {
			mouseXClicked = e.getX();
			originalMouseXClicked = mouseXClicked;
			mouseYClicked = e.getY();
			originalMouseYClicked = mouseYClicked;
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			if(isMouseWithinImageX() && isMouseWithinImageY()) {
				mouseXReleased = e.getX();
				mouseYReleased = e.getY();
				updateImage();
				firstCommand = new TranslateXCommand(perspective, (mouseXReleased - originalMouseXClicked));
				secondCommand = new TranslateYCommand(perspective, (mouseYReleased - originalMouseYClicked));
				command = new TranslateTwoStepCommand(firstCommand, secondCommand);
				invoker.addCommand(command);
			}
		}
		
		@Override
		public void mouseDragged(MouseEvent e) {
			if(isMouseWithinImageX() && isMouseWithinImageY()) {
				mouseXReleased = e.getX();
				mouseYReleased = e.getY();
				if(updateImage()) {
					mouseXClicked = mouseXReleased;
					mouseYClicked = mouseYReleased;
				}
			}
		}
		
		private boolean updateImage() {
			if(changedPosition()) {
				xTranslation = mouseXReleased - mouseXClicked;
				yTranslation = mouseYReleased - mouseYClicked;
				invoker = Invoker.getInstance();
				
				if(USING_LIMIT_OF_FRAME) {
					if(willImageReachNorth()) {
						firstCommand = new TranslateYCommand(perspective, -perspective.getyPosition());
					}
					else if(willImageReachSouth()) {
						int value = imagePanel.getHeight() - (perspective.getyPosition() + ((int)(image.getHeight() * perspective.getZoomPercentage())));
						firstCommand = new TranslateYCommand(perspective, value);
					}
					else {
						int value = mouseYReleased - mouseYClicked;
						firstCommand = new TranslateYCommand(perspective, value);
					}
					
					if(willImageReachEast()) {
						int value = imagePanel.getWidth() - (perspective.getxPosition() + ((int)(image.getWidth() * perspective.getZoomPercentage())));
						secondCommand = new TranslateXCommand(perspective, value);
					}
					else if(willImageReachWest()) {
						secondCommand = new TranslateXCommand(perspective, -perspective.getxPosition());
					}
					else {
						int value = mouseXReleased - mouseXClicked;
						secondCommand = new TranslateXCommand(perspective, value);
					}
				}
				else {
					int value = mouseYReleased - mouseYClicked;
					firstCommand = new TranslateYCommand(perspective, value);
					value = mouseXReleased - mouseXClicked;
					secondCommand = new TranslateXCommand(perspective, value);
				}
				
				command = new TranslateTwoStepCommand(firstCommand, secondCommand);
				invoker.setCommand(command);
				invoker.run();
				
				imagePanel.repaint();
				
				return true;
			}
			
			return false;
		}
		
		private boolean changedPosition() {
			return (mouseXClicked != mouseXReleased) || (mouseYClicked != mouseYReleased);
		}
		
		private boolean isMouseWithinImageX() {
			return ((mouseXClicked >= perspective.getxPosition()) && (mouseXClicked <= (perspective.getxPosition() + ((int)(image.getWidth() * perspective.getZoomPercentage())))));
		}
		
		private boolean isMouseWithinImageY() {
			return ((mouseYClicked >= perspective.getyPosition()) && (mouseYClicked <= (perspective.getyPosition() + ((int)(image.getHeight() * perspective.getZoomPercentage())))));
		}
		
		private boolean willImageReachNorth() {
			return ((yTranslation + perspective.getyPosition()) <= 0);
		}
		
		private boolean willImageReachSouth() {
			return ((yTranslation + perspective.getyPosition() + ((int)(image.getHeight() * perspective.getZoomPercentage()))) > imagePanel.getHeight());
		}
		
		private boolean willImageReachEast() {
			return ((xTranslation + perspective.getxPosition() + ((int)(image.getWidth() * perspective.getZoomPercentage()))) > imagePanel.getWidth());
		}
		
		private boolean willImageReachWest() {
			return ((xTranslation + perspective.getxPosition()) <= 0);
		}
		
	}
	
	class ZoomMouseListener implements MouseWheelListener {
		
		@Override
		public void mouseWheelMoved(MouseWheelEvent e) {
			int value = e.getWheelRotation();
			invoker = Invoker.getInstance();
			if(value > 0) {
				command = new ZoomInCommand(perspective, (value*0.1));
			}
			else {
				command = new ZoomOutCommand(perspective, (value*0.1));
			}
			invoker.setCommand(command);
			invoker.run();
			
			imagePanel.repaint();
			
			invoker.addCommand(command);
		}
		
	}
}